/**
 * @file   dictionary.cpp
 * @author wolfhead <wolfhead@wolfhead-laptop>
 * @date   Fri Oct 21 14:33:23 2011
 * 
 * @brief  
 * 
 * 
 */
#include "dictionary.h"
#include <sstream>
#include <assert.h>
#include "attribute.h"
#include "error.h"

using namespace PP;


Dictionary::Dictionary(
    const DictionaryConfig& config)
    : config_(config)
{
}

Dictionary::~Dictionary()
{
    for (AttrIndexMap::iterator it = attrIndexMap_.begin();
         it != attrIndexMap_.end();
         ++it)
    {
        delete *it;
        *it = NULL;
    }
}

const DictionaryConfig& Dictionary::GetConfig() const
{
    return config_;
}

size_t Dictionary::Size() const
{
    return attrNameMap_.size();
}

Attribute * Dictionary::GetAttribute(const std::string& name) const
{
    AttrNameMap::const_iterator it = attrNameMap_.find(name);
    if (it == attrNameMap_.end())
    {
        return NULL;
    }

    return it->second;
}

Attribute * Dictionary::GetAttribute(size_t index) const
{
    if (index >= attrIndexMap_.size())
    {
        return NULL;
    }

    return attrIndexMap_[index];
}


size_t Dictionary::GetOffset(const std::string& name) const
{
    NameOffsetMap::const_iterator it = nameOffsetMap_.find(name);
    if (it == nameOffsetMap_.end())
    {
        return npos;
    }

    return it->second;
}

Parser * Dictionary::GetParser(const std::string& name) const
{
    Attribute * pAttr = GetAttribute(name);
    if (!pAttr)
    {
        return NULL;
    }

    return pAttr->GetParser();
}

size_t Dictionary::GetSize() const
{
    return dataLen_;
}

size_t Dictionary::GetIndex(const std::string& name) const
{
    NameIndexMap::const_iterator it = nameIndexMap_.find(name);
    if (it == nameIndexMap_.end())
    {
        return npos;
    }

    return it->second;
}

int Dictionary::AppendAttribute(Attribute * pAttr)
{
    assert(pAttr);

    bool alreadyInList = false;
    Attribute * p = NULL;

    AttrNameMap::iterator nameIt = attrNameMap_.find(pAttr->GetName());
    if (nameIt != attrNameMap_.end())
    {     
        // will be deleted in the end
        // delete nameIt->second;
        alreadyInList = true;
        p = nameIt->second;
        nameIt->second = pAttr;
    }
    else
    {
        attrNameMap_[pAttr->GetName()] = pAttr;
    }


    for (AttrIndexMap::iterator indexIt = attrIndexMap_.begin();
         indexIt != attrIndexMap_.end();
         ++indexIt)
    {
        if ((*indexIt)->GetName() == pAttr->GetName())
        {
            assert(p == *indexIt);
            *indexIt = pAttr;
            break;
        }
    }

    // append to attribute list
    if (!alreadyInList)
    {
        nameIndexMap_[pAttr->GetName()] = attrIndexMap_.size();
        attrIndexMap_.push_back(pAttr);
    }
    else
    {
        assert(p);
        delete p;
    }

    return Error::SUCCESS;
}
    
int Dictionary::Initialize(ParserFactory * pParserFactory)
{
    int ret = Error::SUCCESS;

    // Initialize all attribute
    for (AttrIndexMap::iterator it = attrIndexMap_.begin();
         it != attrIndexMap_.end();
         ++it)
    {
        ret = (*it)->Initialize(pParserFactory);
        if (ret != Error::SUCCESS)
        {
            return ret;
        }
    }

    // calculate offset
    // in this version we would only support fix-sized data
    // so it can be caculated in dictionary
    size_t offset = 0;
    for (AttrIndexMap::iterator it = attrIndexMap_.begin();
         it != attrIndexMap_.end();
         ++it)
    {
        Parser * pParser = (*it)->GetParser();
        size_t size;

        ret = pParser->GetLength(size);
        if (ret != Error::SUCCESS)
        {
            return ret;
        }

        nameOffsetMap_[(*it)->GetName()] = offset;
        offset += size;
    }

    // and also we could know the finally data length in dictiionary level
    dataLen_ = offset;

    return 0;
}

std::string Dictionary::ToString() const
{
    std::ostringstream oss;
    oss << "Dictionary\t" << config_.ToString() << std::endl;
    oss << "================================================" << std::endl;
    for (AttrNameMap::const_iterator it = attrNameMap_.begin();
         it != attrNameMap_.end(); 
         ++it)
    {
        oss << it->first << ".\t" << it->second->ToString() << std::endl;
    }

    return oss.str();
}
